﻿// -----------------------------------------------------------------------
// <copyright file="AdminHandler.cs" company="SoftServe">
// Panel for admin which can change some WebServer settings
// </copyright>
// -----------------------------------------------------------------------
namespace WebServer.BusinessLogic.Handlers
{
    using System;
    using System.Collections.Specialized;
    using System.Globalization;
    using System.Text;
    using WebServer.BusinessLogic.Logs;
    using WebServer.BusinessLogic.Web;

    /// <summary>
    /// Handler to process changing settings 
    /// </summary>
    public class AdminHandler : Handler
    {
        /// <summary>
        /// path to admin log out page
        /// </summary>
        public const string AdminLogoutPage = "/admin/Logout.htm";

        /// <summary>
        /// path to admin settings page
        /// </summary>
        protected const string AdminSettingsPage = "/admin/settings.html";

        /// <summary>
        /// path to admin error page
        /// </summary>
        protected const string AdminErrorPage = "/admin/error.html";

        /// <summary>
        /// path to admin logging page
        /// </summary>
        protected const string AdminIndexPage = "/admin/index.html";

        /// <summary>
        /// path to admin logging sucess page
        /// </summary>
        protected const string AdminLoginSucessPage = "/admin/loggined.html";

        /// <summary>
        /// Process http request
        /// </summary>
        /// <param name="request">http request</param>
        /// <returns>outcoming Response object</returns>
        public override Response Handle(Request request)
        {
            // get session
           var session = SessionManager.Instance.GetCurrentSession(request);

            if (request.HttpMethod == EnumHttpMethod.POST)
            {
                if (request.HttpPath.EndsWith(AdminIndexPage, StringComparison.CurrentCulture))
                {
                    // POST /admin/index
                    var a = new StringBuilder("login=");
                    a.Append(Configurator.Instance.AdminLogin.ToString());
                    a.Append("&");
                    string tempLogin = a.ToString();

                    var b = new StringBuilder("password=");
                    b.Append(Configurator.Instance.AdminPassword.ToString());
                    b.Append("\0");
                    string tempPassword = b.ToString();

                    if (request.RawData.Contains("login=") && request.RawData.Contains("password="))
                    {
                        var resp = new Response(request);

                        if (request.RawData.Contains(tempLogin) && request.RawData.Contains(tempPassword))
                        {
                            // string filePath = Configurator.Instance.RelativeWwwPath + "\\admin\\settings.html";
                            // string text = File.ReadAllText(filePath);
                            // var ssiParser=new SsiParser();
                            // text = ssiParser.ParseSsi(text,request);
                            // Byte[] data = this.TextToByteArray(text, Encoding.ASCII);
                            // string MIMEType = "text/html";
                            // string version = request.HttpVersion;

                            // remember session
                            session = SessionManager.Instance.CreateSession(request, resp);

                            // update session as in "Admin mode"
                            session.IsAdmin = true;
                            SessionManager.Instance.UpdateSession(request, session);

                            // log successful attempt
                            Logger.Instance.Log(string.Format(
                                                CultureInfo.CurrentCulture, 
                                                              "-> Admin logged in with IP {0}. Session key is {1}",
                                                              request.UserIpAddress,
                                                              session.SessionKey));

                            // set new location
                            string location = AdminSettingsPage;

                            // move user to sessioned page if IsCookieless
                            if (SessionManager.Instance.IsCookieless)
                            {
                                location = string.Format(CultureInfo.CurrentCulture, "/[{0}]/{1}", session.SessionKey, location.TrimStart(new[] { '/' }));
                            }

                            // create temporary redirect, according to HTTP/1.0 specification
                            resp.SetRedirect(location);                        
                        }
                        else
                        {
                            string location = AdminErrorPage;
                            if (SessionManager.Instance.IsCookieless && session != null)
                            {
                                location = string.Format(CultureInfo.CurrentCulture, "/[{0}]/{1}", session.SessionKey, location.TrimStart(new[] { '/' }));
                            }

                            resp.SetRedirect(location);
                            /* string filePath = Configurator.Instance.RelativeWwwPath + "\\admin\\error.html";
                            string text = File.ReadAllText(filePath);
                            Byte[] data = this.TextToByteArray(text, Encoding.ASCII);
                            string MIMEType = "text/html";
                            string version = request.HttpVersion;
                            return new Response(MIMEType, version, data); */                          
                        }

                        return resp;
                    }
                }
                else if (request.HttpPath.EndsWith(AdminSettingsPage, StringComparison.CurrentCulture))
                {
                    // POST /admin/settings, to save settings
                    if (session != null && session.IsAdmin)
                    {
                        string dataLine =
                            request.RawData.Substring(
                                request.RawData.IndexOf("\r\n\r\n", StringComparison.CurrentCulture) + 4);
                        NameValueCollection parameters =
                                                    System.Web.HttpUtility.ParseQueryString(dataLine);
                        
                        // Setting Port
                        int port = -1;
                        int.TryParse(parameters["port"], out port);
                        if (port > 0)
                        {
                            Configurator.Instance.Port = port;
                        }

                        // setting MaxUsers
                        int users = -1;
                        int.TryParse(parameters["maxusers"], out users);
                        if (users > 0)
                        {
                            Configurator.Instance.MaxUsers = users;
                        }

                        // setting Load balancer port
                        int balancerPort = -1;
                        int.TryParse(parameters["loadbalanceport"], out balancerPort);
                        if (balancerPort > 0)
                        {
                            Configurator.Instance.LoadBalancerPort = balancerPort;
                        }

                        // setting WwwPath
                        string wwwPathLine = parameters["relativewwwpath"];
                        if (!string.IsNullOrEmpty(wwwPathLine))
                        {
                            Configurator.Instance.RelativeWwwPath = System.Web.HttpUtility.UrlDecode(wwwPathLine);
                        }

                        // setting LogPath
                        string logPathLine = parameters["loggerpath"];
                        if (!string.IsNullOrEmpty(logPathLine))
                        {
                            Configurator.Instance.LoggerPath = System.Web.HttpUtility.UrlDecode(logPathLine);
                        }

                        // setting server name
                        string serverNameLine = parameters["servername"];
                        if (!string.IsNullOrEmpty(serverNameLine))
                        {
                            Configurator.Instance.ServerName = serverNameLine;
                        }

                        // setting server mode
                        switch (parameters["mode"].Substring(0, 4))
                        {
                            case "rad1":
                                Configurator.Instance.ServerMode = ServerConfiguration.Normal;
                                break;
                            case "rad2":
                                Configurator.Instance.ServerMode = ServerConfiguration.Redirect;
                                break;
                            case "rad3":
                                Configurator.Instance.ServerMode = ServerConfiguration.LoadBalancer;
                                break;
                            default:
                                Configurator.Instance.ServerMode = Configurator.Instance.ServerMode;
                                break;
                        }

                        // string filePath = Configurator.Instance.RelativeWwwPath + "\\admin\\Loggined.html";
                        // string text = File.ReadAllText(filePath);
                        // byte[] data = this.TextToByteArray(text, Encoding.ASCII);
                        // string MIMEType = "text/html";
                        // string version = request.HttpVersion;
                        // return new Response(MIMEType, version, data);
                        // save data to the file
                        ConfiguratorSerializer.Save();

                        // TODO: move to another, more informative page?
                        request.HttpPath = AdminLoginSucessPage;
                    }
                }
            }

            if (request.HttpMethod == EnumHttpMethod.GET)
            {
                // disable acces to certain files, when not logged in
                // TODO: move this to custom HttpAccess handler and read from files
                if (request.HttpPath.EndsWith(AdminSettingsPage, StringComparison.CurrentCulture) && (session == null || !session.IsAdmin))
                {
                    var resp = new Response(request);
                    resp.SetAccessDenied();
                    return resp;
                }

                // this is not real file, "admin/Logout" is a command for server to log out current user
                if (request.HttpPath.EndsWith(AdminLogoutPage, StringComparison.CurrentCulture))
                {
                    // we have to create new response, because cookies can only be deleted on response
                    // if we move to next handler, we've only got request
                    var resp = new Response();
                    resp.Data = Encoding.UTF8.GetBytes("You have been logged out");

                    // prepare session for removal (in response)
                    if (session != null)
                    {
                        SessionManager.Instance.DeleteSession(session.SessionKey, request, resp);

                        // log logging out process
                        Logger.Instance.Log(string.Format(CultureInfo.CurrentCulture, "<- Admin logged out with IP {0}", request.UserIpAddress));
                    }
                    else
                    {
                        resp.Data = Encoding.UTF8.GetBytes("Logging out failed, because no session was specified.");
                    }

                    // return session removal request
                    return resp;
                }
            }

            return this.NextHandler.Handle(request);
        }
    }
}
